package com.quan.system.web.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.quan.commons.core.bean.R;
import com.quan.commons.core.biz.support.MyBaseController;
import com.quan.commons.core.constant.CommonsConstant;
import com.quan.commons.core.properties.SystemValueProperties;
import com.quan.commons.core.utils.*;
import com.quan.commons.log.annotation.LoginLog;
import com.quan.commons.log.annotation.SysLog;
import com.quan.system.commons.export.SysUserExportVo;
import com.quan.system.commons.vo.SysUserVo;
import com.quan.system.commons.vo.WebSocketMessageVo;
import com.quan.system.entity.SysPermission;
import com.quan.system.entity.SysRole;
import com.quan.system.entity.SysUser;
import com.quan.system.entity.SysUserRole;
import com.quan.system.service.SysRolePermissionService;
import com.quan.system.service.SysUserRoleService;
import com.quan.system.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * 系统-用户
 *
 * @author yhaoquan
 * @email yhaoquan@163.com
 * @date 2021-01-04 22:24:24
 */
@Slf4j
@Api(tags = "系统-用户")
@RestController
@RequestMapping("/system/sysuser")
public class SysUserController extends MyBaseController {

    @Autowired
    private SysUserService service;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SystemValueProperties properties;

    @Autowired
    private SimpMessagingTemplate messagingTemplate ;

    /**
     * 保存
     * @param vo
     * @return
     */
    @PostMapping("save")
    public R save(@Valid @RequestBody SysUserVo vo) {
        this.service.saveUser(vo);
        return R.ok();
    }

    /**
     * 修改
     * @param vo
     * @return
     */
    @PostMapping("update")
    public R update(@Valid @RequestBody SysUserVo vo) {
        this.service.updateUser(vo);
        return R.ok();
    }

    /**
     * 删除
     * @param ids
     * @return
     */
    @PostMapping("delete")
    public R delete(@RequestBody Long[] ids) {
        if (null != ids && ids.length > 0) {
            this.service.removeByIds(Arrays.asList(ids));
            return R.ok();
        } else {
            return R.failure();
        }
    }

    /**
     * 多条件查询信息详情
     * @param vo
     * @return
     */
    @GetMapping("/info")
    public R info(SysUserVo vo) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>(vo);
        SysUser sysUser = this.service.getOne(queryWrapper);

        SysUserVo userVo = new SysUserVo();
        BeanUtils.copyProperties(sysUser, userVo);

        // 获取用户对于的角色ID
        final List<SysUserRole> roleIds = this.sysUserRoleService.getRoleIdsByUserId(vo.getId());
        userVo.setRoleIds(roleIds.stream().map(item -> item.getRoleId()).toArray(Long[]::new));

        return R.ok().put("data", userVo);
    }

    /**
     * 根据ID查询信息详情
     * @param {id}
     * @return
     */
    @GetMapping("/info/{id}")
    public R info(@PathVariable("id") Long id) {
        SysUser sysUser = this.service.getById(id);

        SysUserVo userVo = new SysUserVo();
        BeanUtils.copyProperties(sysUser, userVo);

        // 获取用户对于的角色ID
        final List<SysUserRole> roleIds = this.sysUserRoleService.getRoleIdsByUserId(id);
        userVo.setRoleIds(roleIds.stream().map(item -> item.getRoleId()).toArray(Long[]::new));

        return R.ok().put("data", userVo);
    }

    /**
     * 列表查询
     * @param vo
     * @return
     */
    @GetMapping(value = "list")
    public Object list(SysUserVo vo) {
        List<SysUserVo> list = this.service.queryList(new PageUtils(request), vo);
        return R.ok().put("data", list);
    }

    /**
     * 分页查询
     * @param vo
     * @return
     */
    @SysLog("查询系统用户列表")
    @GetMapping(value = "page")
    public R queryPage(SysUserVo vo) {
        PageUtils page = this.service.queryPage(new PageUtils(request), vo);
        return R.ok().put("data", page);
    }

    /**
     * 修改用户状态
     * @param id
     * @param status
     * @return
     */
    @GetMapping(value = "/changeStatus/{id}/{status}")
    public R changeStatus(@PathVariable Long id, @PathVariable Integer status) {
        this.service.changeStatus(id, status);
        return R.ok();
    }


    /**
     * 用户登录
     * @param vo
     * @return
     */
    @LoginLog(type = CommonsConstant.LogTypeEnums.LOGIN, value = "用户登录")
    @PostMapping("login")
    public R login(@RequestBody SysUserVo vo) {
        final String token = this.service.login(vo);

        if(StringUtils.isNotBlank(token)) {
            OnlineUtils.setOnlineUserPools(this.service.getUserInfoByToken(token));
        }

        return R.ok("登录成功").put("token", token);
    }

    /**
     * 退出登录
     * @return
     */
    @GetMapping("logout")
    public R logout() {
        String token = this.request.getHeader("token");

        if(StringUtils.isNotBlank(token)) {
            final String userId = JwtUtils.getUserId(token, this.properties.getJwt().getSecret());
            final String userName = JwtUtils.getUserName(token, this.properties.getJwt().getSecret());
            if (null != userId) {
                this.redisUtils.del(CommonsConstant.RedisPrefix.SSO_TOKEN + ":" + userId);

                // 用户退出登录，下线
                OnlineUtils.setUnlineUserPools(Long.parseLong(userId));

                return R.ok().put("userName", userName);
            } else {
                log.info("Token解析失败");
                return R.failure("Token解析失败");
            }
        } else {
            return R.ok().put("username", "用户信息过时已销毁");
        }

    }

    /**
     * 获取在线用户
     * @param userVo
     */
    @GetMapping("online")
    public R online(SysUserVo userVo) {
        final ConcurrentHashMap<Long, SysUserVo> onlineUserPools = OnlineUtils.getOnlineUserPools();

        final List<SysUserVo> collect = onlineUserPools.entrySet().stream().map(e -> {
            SysUserVo bean = new SysUserVo();
            BeanUtils.copyProperties(e.getValue(), bean);
            return bean;
        }).collect(Collectors.toList());

        return R.ok().put("total", OnlineUtils.getOnlineNumber()).put("data", collect) ;
    }

    /**
     * 强制下线
     * @param ids
     * @return
     */
    @PostMapping("forceUnline")
    public R forceUnline(@RequestBody Long[] ids) {
        if (null != ids && ids.length > 0) {
            for (Long id : ids) {
                this.redisUtils.del(CommonsConstant.RedisPrefix.SSO_TOKEN + ":" + id);

                // 强制用户下线
                OnlineUtils.setUnlineUserPools(id);

                WebSocketMessageVo message = new WebSocketMessageVo();
                message.setFrom("系统");
                message.setText("强制下线通知，请过5分钟后再登录。");
                this.messagingTemplate.convertAndSendToUser(id.toString(), "/force", JSON.toJSONString(message));
            }
            return R.ok();
        } else {
            return R.failure();
        }
    }

    /**
     * 获取用户信息
     * @param token
     * @return
     */
    @GetMapping("getUserInfoByToken")
    public R getUserInfoByToken(@RequestParam(required = true) String token) {
        // 用户信息
        SysUserVo user = this.service.getUserInfoByToken(token);

        // 用户角色
        final List<SysRole> roles = this.service.getUserRoles(user.getId());

        // 获取用户权限
        final List<SysPermission> permissions = this.service.getUserPermissions(user.getId());

        // UI访问权限列表
        List<String> access = null;
        if(null != permissions && !permissions.isEmpty()) {
            access = new ArrayList<String>();
            for (SysPermission permission : permissions) {
                access.add(permission.getPermission());
            }
        }

        return R.ok().put("user", user).put("roles", roles).put("access", access);
    }

    /**
     * 根据用户角色ID获取用户对应的权限关联关系数据
     * @param roleIds
     * @return
     */
    @RequestMapping(value = "/getRolesPermitByUserRoleIds")
    public Object getRolesPermitByUserRoleIds(@RequestBody List<Long> roleIds) {
        return R.ok().put("data", this.sysRolePermissionService.getPermissionByRoleIds(roleIds));
    }

    /**
     * 重置用户登陆密码为[123456]
     * @param ids
     * @return
     */
    @PostMapping("/batchResetPassword")
    public Object batchResetPassword(@RequestBody List<Long> ids) {
        boolean flag = this.service.batchResetPassword(ids);
        if (flag) {
            return R.ok();
        } else {
            return R.failure("重置用户登陆密码失败：[ " + ids + " ]");
        }
    }


    /**
     * 修改个人登录密码
     * @param vo
     * @return
     */
    @ApiOperation(value = "修改个人登录密码")
    @PostMapping(value = "updateMyPassword")
    public Object updateMyPassword(@RequestBody SysUserVo vo) {
        try {
            if (StringUtils.isBlank(vo.getOldPassword())) {
                return R.failure("原密码不能为空");
            }
            if (StringUtils.isBlank(vo.getNewPassword())) {
                return R.failure("新密码不能为空");
            }
            this.service.updatePassword(vo.getId(), vo.getOldPassword(), vo.getNewPassword());
            return R.ok();
        } catch (RuntimeException e) {
            return R.failure(e.getMessage());
        }
    }

    /**
     * 修改个人基本信息
     * @param entity
     * @return
     */
    @ApiOperation(value = "修改个人基本信息")
    @PostMapping(value = "updateMyInfo")
    public Object updateMyInfo(@RequestBody SysUser entity) {
        if (StringUtils.isBlank(entity.getRealname())) {
            return R.failure("姓名不能为空");
        }
        if (StringUtils.isBlank(entity.getEmail())) {
            return R.failure("邮件地址不能为空");
        }
        if (StringUtils.isBlank(entity.getMobile())) {
            return R.failure("手机号码不能为空");
        }

        entity.setPassword(null);
        entity.setSalt(null);
        this.service.updateById(entity);

        return R.ok();
    }

    @PostMapping("export")
    public void code(@RequestBody SysUserVo vo) throws IOException {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>(vo);

        List<SysUser> list = this.service.list(queryWrapper);

        try {
            if(null != list && !list.isEmpty()) {
                // 组装数据
                List<SysUserExportVo> objList = new ArrayList<SysUserExportVo>();

                for (SysUser user : list) {
                    SysUserExportVo ee = new SysUserExportVo() ;
                    BeanUtil.copyProperties(user, ee);
                    objList.add(ee);
                }

                // 设置模板
                TemplateExportParams params = new TemplateExportParams("export/system_user.xlsx", true);

                // 模板数据
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("now", DateUtils.getDate());
                map.put("list", objList);

                // 导出
                Workbook workbook = ExcelExportUtil.exportExcel(params, map);
                // 文件名称
                String filename = "系统用户信息" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+".xlsx";
                // 客户端下载
                WebUtils.download(response, workbook, filename);
            }

        } catch (Exception e) {}
    }
}
